package session

import (
	"context"
	"cybertwin/db/redis/redisconn"
	db "cybertwin/db/sqlc"
	"cybertwin/goclient"
	"cybertwin/utils/configtools"
	"cybertwin/utils/constants"
	"cybertwin/utils/generator"
	"database/sql"
	"fmt"
	"strings"
	"time"

	// "cybertwin/utils/generator"
	"cybertwin/utils/stringutils"
	// "database/sql"

	_ "github.com/lib/pq"
	log "github.com/sirupsen/logrus"
)

// checkDBConfigValid 当DatabaseConfiguration中的"dbSource"或"dbDriver"中有任意为空，就返回false，否则返回true
func checkDBConfigEmptyValid() bool {
	configtools.DatabaseConfiguration.GetString("dbSource")
	configtools.DatabaseConfiguration.GetString("dbDriver")
	return !stringutils.IsEmpty(configtools.DatabaseConfiguration.GetString("dbSource")) &&
		!stringutils.IsEmpty(configtools.DatabaseConfiguration.GetString("dbDriver"))
}

func (txQuery *DBTXQuery) UeRegisterTX(ctx context.Context, param UeRegisterTXParam) (db.InsertRegisteredUeRow, error) {
	var res db.InsertRegisteredUeRow
	var err error
	err = txQuery.execTx(ctx, func(txQuery *db.Queries) error {
		// 1. 新增注册设备
		res, err = txQuery.InsertRegisteredUe(ctx, param.InsertRegisteredUeParam)
		if err != nil {
			log.Errorln("[UeRegisterTX]-[InsertRegisteredUe]-返回error", err.Error())
			return err
		}
		// 2. 关联该设备的user，cybertwin。由于数据库中我已经绑定外键关系，因此不需要在程序里面校验uid和cybertwinid的合法性
		_, err = txQuery.InsertUeDetail(ctx, db.InsertUeDetailParams{
			Ueid:        param.InsertRegisteredUeParam.Ueid,
			Uid:         param.Uid,
			CybertwinID: param.InsertRegisteredUeParam.Cybertwinid,
			Status: sql.NullString{
				String: "OFFLINE",
				Valid:  false,
			},
		})
		if err != nil {
			return err
		}
		// 3. 在redis中加入与该设备关联的哈希表
		redisConn := redisconn.Conn
		hashKey := fmt.Sprintf("%s:%s:te_req", param.Uid, param.InsertRegisteredUeParam.Ueid)
		err = redisConn.HSet(context.Background(), hashKey,
			"normalCount", 0,
			"sensiCount", 0,
			"authCount", 0,
			"illegalCount", 0,
			"activeDevice", false,
			"activeZone", false,
		).Err()
		if err != nil {
			log.Errorf("[UeRegisterTX]-[InsertRegisteredUe]-返回error: %s", err)
			return err
		}
		// 4. 在redis中加入与该设备关联的服务表
		// TODO：目前这个表全局唯一，后续可能需要调整
		return nil
	}, // end of 匿名函数
	)
	return res, err
}

func (txQuery *DBTXQuery) UserRegisterTX(ctx context.Context, param db.InsertUserByIdParams) (db.InsertCybertwinByIdRow, error) {
	var res db.InsertCybertwinByIdRow
	var err error

	// 获取当用函数此时是否为集群内pod
	inCluster := configtools.EnvConfiguration.GetBool(configtools.INCLUSTER)
	log.Infof("[dbfunc]-[UserRegisterTX]-获取到INCLUSTER值为%v", inCluster)

	newCtid := generator.GenerateCtid(param.Uid)

	// 定义注册用户的事务函数
	// var registerUserFunc func(txQuery *db.Queries) error
	registerUserFunc := func(txQuery *db.Queries) (err error) {
		// 1. 调用client-go接口创建ct
		uid := strings.Replace(param.Uid, "_", "-", 1) // 注：k8s命名中不支持"_"，因此把"_"替换为"-"
		createRes, err := goclient.CreateByYAML("k8syaml/ct/ct_total.yaml", inCluster,
			goclient.WithUidAdd(uid),
			goclient.WithEnvAdd(goclient.Env{Key: constants.UidEnvFlag, Value: param.Uid}, goclient.Env{Key: constants.CtidEnvKey, Value: newCtid}),
		)
		if createRes == -1 {
			log.Errorln("[UserRegisterTX]-通过ct_total.yaml创建ct失败")
			return
		} else if createRes == -2 {
			log.Errorln("[UserRegisterTX]-通过ct_total.yaml创建ct失败且存在回滚失败，需手动删除资源")
			return
		}
		// 等待svc资源被创建出来
		time.Sleep(time.Second * 1)

		// 2. 返回nodePort
		cybertwinSvcName := "cybertwin-" + uid // 此处的字符串"cyebrtwin"需要和ct_total中的svc的name相同
		nodePort, err := goclient.GetSvcPort(cybertwinSvcName, "default", inCluster)
		if err != nil {
			log.Errorln("[UserRegisterTX]-[GetSvcPort]-返回error, err=", err)
			return
		}

		log.Infof("[UserRegisterTX]-得到cybertwin的nodeport=%d", nodePort)

		// 3. db新增注册用户
		_, err = txQuery.InsertUserById(ctx, param)
		if err != nil {
			log.Errorln("[UserRegisterTX]-[InsertUserById]-返回error", err.Error())
			return
		}

		// 4. db绑定用户与ctid
		insertCybertwinByIdParams := db.InsertCybertwinByIdParams{
			Ctid:     newCtid,
			Uid:      param.Uid,
			Port:     nodePort,
			Ipv4Addr: "10.176.40.183", // todo: 目前直接硬编码,cic003的地址
		}
		res, err = txQuery.InsertCybertwinById(ctx, insertCybertwinByIdParams)
		if err != nil {
			log.Errorln("[UserRegisterTX]-[InsertCybertwinById]-返回error", err.Error())
			return
		}

		// todo: 5. 插入与用户/cybertwin关联的服务阈值访问表
		// 目前版本中，服务阈值访问表全局唯一

		return nil
	}
	// 如果不在集群里，访问本地 ct
	if !inCluster {
		registerUserFunc = func(txQuery *db.Queries) (err error) {
			// 1. db新增注册用户
			_, err = txQuery.InsertUserById(ctx, param)
			if err != nil {
				log.Errorln("[UserRegisterTX]-[InsertUserById]-返回error", err.Error())
				return err
			}

			// 2. db绑定用户与ctid
			insertCybertwinByIdParams := db.InsertCybertwinByIdParams{
				Ctid:     newCtid,
				Uid:      param.Uid,
				Port:     8888,
				Ipv4Addr: "127.0.0.1", // todo: 目前直接硬编码,本地地址
			}
			fmt.Println("用户", newCtid)
			res, err = txQuery.InsertCybertwinById(ctx, insertCybertwinByIdParams)
			if err != nil {
				log.Errorln("[UserRegisterTX]-[InsertCybertwinById]-返回error", err.Error())
				return
			}
			return
		}
	}
	err = txQuery.execTx(ctx, registerUserFunc)
	return res, err
}
